/*******************************************************************
 *  Copyright(c) 2022-2025 Ltd.
 *  All right reserved. See LGPL for detailed Information
 *
 *  文件名称: qohappcontext.cpp
 *  简要描述: 主题相关处理类
 *  创建日期: 2025/06/18
 *  作者: WangHao
 *  说明:
 *
 *  修改日期:
 *  作者:
 *  说明:
 ******************************************************************/
#include <bit>
#include <mutex>
#include <qdebug.h>
#include <qjsobject.h>
#include <QScopedPointer>
#include <private/qobject_p.h>
#include <qpa/qplatformtheme.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/private/qguiapplication_p.h>

#include "qohappcontext.h"

namespace {
enum class OhConfigurationColorMode
{
    COLOR_MODE_NOT_SET = -1,	/* 表示未设置颜色模式 */
    COLOR_MODE_DARK = 0,	/* 表示深色模式 */
    COLOR_MODE_LIGHT = 1	/* 表示浅色模式 */    
};

static QOhAppContext::ColorMode sysColorMode2ColorMode(OhConfigurationColorMode colorMode)
{
    switch (colorMode) {
    case ::OhConfigurationColorMode::COLOR_MODE_LIGHT:
        return QOhAppContext::ColorMode::Light;
    case ::OhConfigurationColorMode::COLOR_MODE_DARK:
        return QOhAppContext::ColorMode::Dark;
    case ::OhConfigurationColorMode::COLOR_MODE_NOT_SET:
        return QOhAppContext::ColorMode::Default;
    }

    qWarning("%s: got unknown ColorMode: %d", Q_FUNC_INFO, static_cast<int>(colorMode));
    return QOhAppContext::ColorMode::Default;
}

}

class QOhAppContextPrivate : public QObjectPrivate
{
    Q_DECLARE_PUBLIC(QOhAppContext)
public:
    ~QOhAppContextPrivate();

protected:
    void initialized();
    bool darkColorModeActive() const;

private:    
    bool m_followSystemColorMode = false;
    Napi::FunctionReference m_callbackRef;
    inline static std::once_flag ms_once { };
    inline static QScopedPointer<QOhAppContext> ms_appContext { nullptr };

    QOhAppContext::ColorMode m_colorMode = QOhAppContext::ColorMode::Default;
    OhConfigurationColorMode m_sysColorMode = OhConfigurationColorMode::COLOR_MODE_LIGHT;
};

QOhAppContextPrivate::~QOhAppContextPrivate()
{
    m_callbackRef.Reset();
}

void QOhAppContextPrivate::initialized()
{
    void* context = QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("UIAbilityContext");
    if (nullptr == context) {
        qWarning() << "UIAbilityContext is null.";
        return;
    }

    if (QJsObject *jsContext = std::bit_cast<QJsObject*>(context)) {
        QtOh::runOnJsUIThreadAndWait([&]{
            Napi::Object config = jsContext->get("config").ToObject();
            if (!config.IsNull())
                m_sysColorMode = OhConfigurationColorMode(config.Get("colorMode").ToNumber().Int32Value());

            Napi::Object environmentCallback = Napi::Object::New(jsContext->env());
            Napi::Function configurationUpdated = Napi::Function::New(environmentCallback.Env(), [this](const Napi::CallbackInfo &info){
                if (0 >= info.Length())
                    return;

                Napi::Object config = info[0].ToObject();
                Napi::Value value = config.Get("colorMode");
                OhConfigurationColorMode colorMode = OhConfigurationColorMode(value.ToNumber().Int32Value());
                if(m_followSystemColorMode)
                    QMetaObject::invokeMethod(qApp, [colorMode]{
                        QGuiApplicationPrivate::platformTheme()->setThemeColorMode(int(colorMode));
                    }, Qt::QueuedConnection);

                m_sysColorMode = colorMode;
            });
            m_callbackRef = Napi::Persistent(configurationUpdated);
            environmentCallback.Set("onConfigurationUpdated", configurationUpdated);

            QJsObject appContext(jsContext->call("getApplicationContext").ToObject());
            appContext.call("on", { Napi::String::From(appContext.env(), "environment"), environmentCallback });
        });
    } else {
        qWarning() << Q_FUNC_INFO << "get uiabilitycontext failed.";
    }
}

bool QOhAppContextPrivate::darkColorModeActive() const
{
    return QGuiApplicationPrivate::platformTheme()->darkThemeEnabled();
}

QOhAppContext::QOhAppContext(QObject *parent)
    : QObject(*(new QOhAppContextPrivate()), parent)
{
    qRegisterMetaType<QOhAppContext::ColorMode>();
    d_func()->initialized();
}

QOhAppContext::~QOhAppContext()
{

}

QOhAppContext *QOhAppContext::instance()
{
    std::call_once(QOhAppContextPrivate::ms_once, []{
        QOhAppContextPrivate::ms_appContext.reset(new QOhAppContext());        
    });

    return QOhAppContextPrivate::ms_appContext.get();
}

void QOhAppContext::setColorMode(ColorMode mode)
{
    Q_D(QOhAppContext);
    auto calcNewColorMode = [d](auto mode) {
        switch (mode) {
        case ColorMode::Dark:
            return ColorMode::Dark;
        case ColorMode::Light:
            return ColorMode::Light;
        case ColorMode::Default:
            return ColorMode::Default;
        case ColorMode::FollowSystemSetting:
            return ::sysColorMode2ColorMode(d->m_sysColorMode);
        };
        qWarning("%s: got unknown ColorThemeMode: %d", Q_FUNC_INFO, static_cast<int>(mode));
        return ColorMode::Default;
    };

    d->m_followSystemColorMode = (ColorMode::FollowSystemSetting == mode);
    auto newColorMode = calcNewColorMode(mode);
    if (d->m_colorMode != newColorMode) {
        d->m_colorMode = newColorMode;
        QGuiApplicationPrivate::platformTheme()->setThemeColorMode(int(newColorMode));
        Q_EMIT colorModeChanged(d->m_colorMode, QPrivateSignal());
    }
}

QOhAppContext::ColorMode QOhAppContext::colorMode() const
{
    Q_D(const QOhAppContext);
    return d->m_colorMode;
}
